 /*
 * This parser understands the following LL1 grammar
 * <bexp> ::= <bexp> '||' <bterm>
 * <bexp> ::= <bterm>
 * <bterm> ::= <bterm> '&&' <bfactor>
 * <bterm> ::= <bfactor>
 * <bfactor> ::= NOT <bfactor>
 * <bfactor> ::= '(' <bexp> ')'
 * <bfactor> ::= 'time' <comparisonOp> <constantValue>  
 * <bfactor> ::= 'messageKind' == <constantValue>
 * <bfactor> ::= 'existField[' <string> ']'
 * <bfactor> ::= 'notExistField[' <string> ']'
 * <bfactor> ::= 'messageField['  <string> ']' <comparisonOp> <comparisonValue>
 * <comparisonOp> ::= '=' | '!=' | '>' | '<'
 * <comparisonValue>::= 'readField[' <string> ']' 
 * <constantValue> ::= anything between two '
 * <string> //anything between two "
 * 
 * 
 */
package it.unisannio.lesim.fsm;

import it.unisannio.lesim.fsm.exception.UnrecognizedTokenException;
import it.unisannio.lesim.fsm.exception.UnrecognizedExpressionException;
import java.util.Map;

/**
 *
 * @author Marco Calisti
 * @author Antonio Cuomo
 * @author Rocco Mazzeo
 * @author Francesco Pacilio
 * 
 */

public class BooleanExpressionEvaluator {
    
    MyTokenizer scanner;
    Map fieldsToValues;
    String messageKind;
    long time;
    long messageTime;
    Map storage;
    
    public boolean evaluateBooleanExpression(String expression, Map storage, String messageKind, Map fieldsToValues, long time, long messageTime ) throws UnrecognizedExpressionException{
        this.scanner= new MyTokenizer(expression);
        this.fieldsToValues= fieldsToValues;
        this.messageKind= messageKind;
        this.time=time;
        this.messageTime=messageTime; 
        this.storage=storage;
        return evalBExp();
    }
    
    private boolean evalBExp() throws UnrecognizedExpressionException {
        try {
            boolean firstValue = evalBTerm();
            scanner.consumeToken();
            if (scanner.lastTokenType() == MyTokenizer.OR_OPERATOR) {
                return firstValue || evalBTerm();
            } 
            else if (scanner.lastTokenType()==MyTokenizer.END_REACHED)
                return firstValue;
            else {
                throw new UnrecognizedExpressionException();
            }
        } catch (UnrecognizedTokenException ex) {
             throw new UnrecognizedExpressionException();
        }
    }
    
    private boolean evalBTerm() throws UnrecognizedExpressionException {
        try {
            boolean firstValue = evalBFactor();
            scanner.consumeToken();
            if (scanner.lastTokenType() == MyTokenizer.AND_OPERATOR) {
                return firstValue && evalBFactor();
            } 
            else if (scanner.lastTokenType()==MyTokenizer.END_REACHED)
                return firstValue;
            else {
                throw new UnrecognizedExpressionException();
            }
        } catch (UnrecognizedTokenException ex) {
            throw new UnrecognizedExpressionException();
        }
    }    

    
    private boolean evalBFactor() throws UnrecognizedExpressionException {
        try {
            scanner.consumeToken();
            if (scanner.lastTokenType() == MyTokenizer.END_REACHED)
                return true;
            else if (scanner.lastTokenType() == MyTokenizer.NOT_OPERATOR) {
                return !evalBFactor();
            } 
            else if (scanner.lastTokenType() == MyTokenizer.LEFT_ROUND_PAR) {
                boolean innerExp = evalBExp();
                scanner.consumeToken();
                if (scanner.lastTokenType() == MyTokenizer.RIGHT_ROUND_PAR) {
                    return innerExp;
                } else {
                    throw new UnrecognizedExpressionException();
                }
            }
            else if (scanner.lastTokenType() == MyTokenizer.TIME) {
                scanner.consumeToken();
                if (scanner.lastTokenType() == MyTokenizer.EQUALITY_OPERATOR) {
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    return this.time == Long.parseLong(scanner.lastLexeme());
                }
                else if (scanner.lastTokenType() == MyTokenizer.DISEQUALITY_OPERATOR) {
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    return this.time != Long.parseLong(scanner.lastLexeme());
                }
                else if (scanner.lastTokenType() == MyTokenizer.LT_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    return this.time < Long.parseLong(scanner.lastLexeme());
                
                }
                else if (scanner.lastTokenType() == MyTokenizer.GT_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    return this.time > Long.parseLong(scanner.lastLexeme());
                }
                else if (scanner.lastTokenType() == MyTokenizer.GE_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    return this.time >= Long.parseLong(scanner.lastLexeme());
                }
                else if (scanner.lastTokenType() == MyTokenizer.LE_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    return this.time <= Long.parseLong(scanner.lastLexeme());
                }
                else throw new UnrecognizedExpressionException();
            }
            else if (scanner.lastTokenType() == MyTokenizer.TIME_DIFF) {
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.LEFT_SQUARE_PAR) {
                    throw new UnrecognizedExpressionException();
                }
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.STRING) {
                    throw new UnrecognizedExpressionException();
                }
                String varName = scanner.lastLexeme();
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR) {
                    throw new UnrecognizedExpressionException();
                }
                String savedTimeString=(String) storage.get(varName);
                long savedTime= Long.parseLong(savedTimeString);
                long diffTime= messageTime-savedTime;
                scanner.consumeToken();
                if (scanner.lastTokenType() == MyTokenizer.EQUALITY_OPERATOR) {
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    long value= Long.parseLong(scanner.lastLexeme());
                    return diffTime == value;
                } 
                else if (scanner.lastTokenType() == MyTokenizer.DISEQUALITY_OPERATOR) {
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    long value= Long.parseLong(scanner.lastLexeme());
                    return diffTime != value;
                } 
                else if (scanner.lastTokenType() == MyTokenizer.LT_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    long value= Long.parseLong(scanner.lastLexeme());
                    return diffTime < value;
                }
                else if (scanner.lastTokenType() == MyTokenizer.GT_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    long value= Long.parseLong(scanner.lastLexeme());
                    return diffTime > value;
                }
                else if (scanner.lastTokenType() == MyTokenizer.LE_OPERATOR){
                   scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    long value= Long.parseLong(scanner.lastLexeme());
                    return diffTime <= value;
                }
                else if (scanner.lastTokenType() == MyTokenizer.GE_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    long value= Long.parseLong(scanner.lastLexeme());
                    return diffTime >= value;
                }
                else 
                    throw new UnrecognizedExpressionException();
            } 
            else if (scanner.lastTokenType() == MyTokenizer.MESSAGE_KIND) {
                scanner.consumeToken();
                if (scanner.lastTokenType() == MyTokenizer.EQUALITY_OPERATOR) {
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    return this.messageKind.equalsIgnoreCase(scanner.lastLexeme());
                }
                if (scanner.lastTokenType() == MyTokenizer.DISEQUALITY_OPERATOR) {
                    scanner.consumeToken();
                    if(scanner.lastTokenType() != MyTokenizer.CONSTANT_VALUE)
                        throw new UnrecognizedExpressionException();
                    return !this.messageKind.equalsIgnoreCase(scanner.lastLexeme());
                }
                else 
                    throw new UnrecognizedExpressionException();
            } 
            else if (scanner.lastTokenType() == MyTokenizer.EXIST_FIELD) {
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.LEFT_SQUARE_PAR) {
                    throw new UnrecognizedExpressionException();
                }
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.STRING) {
                    throw new UnrecognizedExpressionException();
                }
                String fieldName = scanner.lastLexeme();
                boolean retValue=fieldsToValues.containsKey(fieldName);
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR) {
                    throw new UnrecognizedExpressionException();
                }
                return retValue;
            } 
            
            else if (scanner.lastTokenType() == MyTokenizer.MESSAGE_FIELD) {
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.LEFT_SQUARE_PAR) {
                    throw new UnrecognizedExpressionException();
                }
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.STRING) {
                    throw new UnrecognizedExpressionException();
                }
                String fieldName = scanner.lastLexeme();
                FieldValue field= (FieldValue) fieldsToValues.get(fieldName);
                scanner.consumeToken();
                if (scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR) {
                    throw new UnrecognizedExpressionException();
                }
                scanner.consumeToken();
                if (scanner.lastTokenType() == MyTokenizer.EQUALITY_OPERATOR) {
                    scanner.consumeToken();
                    if(scanner.lastTokenType() == MyTokenizer.CONSTANT_VALUE){
                    return field.getValue().equalsIgnoreCase(scanner.lastLexeme());
                    }
                    else if(scanner.lastTokenType() == MyTokenizer.READ_FIELD_COMMAND){
                        scanner.consumeToken();
                        if (scanner.lastTokenType()!= MyTokenizer.LEFT_SQUARE_PAR)
                            throw new UnrecognizedExpressionException();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.STRING)
                                throw new UnrecognizedExpressionException();
                        String varName= scanner.lastLexeme();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR)
                                throw new UnrecognizedExpressionException();
                        String savedField= (String) storage.get(varName);
                        return field.getValue().equalsIgnoreCase(savedField);
                    }
                    else
                        throw new UnrecognizedExpressionException();
                } 
                else if (scanner.lastTokenType() == MyTokenizer.DISEQUALITY_OPERATOR) {
                    scanner.consumeToken();
                    if(scanner.lastTokenType() == MyTokenizer.CONSTANT_VALUE){
                    return field.getValue().equalsIgnoreCase(scanner.lastLexeme());
                    }
                    else if(scanner.lastTokenType() == MyTokenizer.READ_FIELD_COMMAND){
                        scanner.consumeToken();
                        if (scanner.lastTokenType()!= MyTokenizer.LEFT_SQUARE_PAR)
                            throw new UnrecognizedExpressionException();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.STRING)
                                throw new UnrecognizedExpressionException();
                        String varName= scanner.lastLexeme();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR)
                                throw new UnrecognizedExpressionException();
                        String savedField= (String) storage.get(varName);
                        return !field.getValue().equalsIgnoreCase(savedField);
                    }
                    else
                        throw new UnrecognizedExpressionException();
                } 
                    
                else if (scanner.lastTokenType() == MyTokenizer.LT_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() == MyTokenizer.CONSTANT_VALUE){
                        int fieldIntValue= Integer.parseInt(field.getValue());
                        int intValue= Integer.parseInt(scanner.lastLexeme());
                        return fieldIntValue< intValue;
                    }
                    else if(scanner.lastTokenType() == MyTokenizer.READ_FIELD_COMMAND){
                        scanner.consumeToken();
                        if (scanner.lastTokenType()!= MyTokenizer.LEFT_SQUARE_PAR)
                            throw new UnrecognizedExpressionException();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.STRING)
                                throw new UnrecognizedExpressionException();
                        String varName= scanner.lastLexeme();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR)
                                throw new UnrecognizedExpressionException();
                        String savedField= (String) storage.get(varName);
                        int fieldIntValue= Integer.parseInt(field.getValue());
                        int intValue= Integer.parseInt(savedField);
                        return fieldIntValue< intValue;
                   }
                    else 
                        throw new UnrecognizedExpressionException();
                }
                else if (scanner.lastTokenType() == MyTokenizer.GT_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() == MyTokenizer.CONSTANT_VALUE){
                        int fieldIntValue= Integer.parseInt(field.getValue());
                        int intValue= Integer.parseInt(scanner.lastLexeme());
                        return fieldIntValue> intValue;
                    }
                    else if(scanner.lastTokenType() == MyTokenizer.READ_FIELD_COMMAND){
                        scanner.consumeToken();
                        if (scanner.lastTokenType()!= MyTokenizer.LEFT_SQUARE_PAR)
                            throw new UnrecognizedExpressionException();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.STRING)
                                throw new UnrecognizedExpressionException();
                        String varName= scanner.lastLexeme();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR)
                                throw new UnrecognizedExpressionException();
                        String savedField= (String) storage.get(varName);
                        int fieldIntValue= Integer.parseInt(field.getValue());
                        int intValue= Integer.parseInt(savedField);
                        return fieldIntValue > intValue;
                   }
                    else 
                        throw new UnrecognizedExpressionException();
                }
                else if (scanner.lastTokenType() == MyTokenizer.LE_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() == MyTokenizer.CONSTANT_VALUE){
                        int fieldIntValue= Integer.parseInt(field.getValue());
                        int intValue= Integer.parseInt(scanner.lastLexeme());
                        return fieldIntValue<= intValue;
                    }
                    else if(scanner.lastTokenType() == MyTokenizer.READ_FIELD_COMMAND){
                        scanner.consumeToken();
                        if (scanner.lastTokenType()!= MyTokenizer.LEFT_SQUARE_PAR)
                            throw new UnrecognizedExpressionException();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.STRING)
                                throw new UnrecognizedExpressionException();
                        String varName= scanner.lastLexeme();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR)
                                throw new UnrecognizedExpressionException();
                        String savedField= (String) storage.get(varName);
                        int fieldIntValue= Integer.parseInt(field.getValue());
                        int intValue= Integer.parseInt(savedField);
                        return fieldIntValue <= intValue;
                   }
                    else 
                        throw new UnrecognizedExpressionException();
                }
                else if (scanner.lastTokenType() == MyTokenizer.GE_OPERATOR){
                    scanner.consumeToken();
                    if(scanner.lastTokenType() == MyTokenizer.CONSTANT_VALUE){
                        int fieldIntValue= Integer.parseInt(field.getValue());
                        int intValue= Integer.parseInt(scanner.lastLexeme());
                        return fieldIntValue>= intValue;
                    }
                    else if(scanner.lastTokenType() == MyTokenizer.READ_FIELD_COMMAND){
                        scanner.consumeToken();
                        if (scanner.lastTokenType()!= MyTokenizer.LEFT_SQUARE_PAR)
                            throw new UnrecognizedExpressionException();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.STRING)
                                throw new UnrecognizedExpressionException();
                        String varName= scanner.lastLexeme();
                        scanner.consumeToken();
                        if(scanner.lastTokenType() != MyTokenizer.RIGHT_SQUARE_PAR)
                                throw new UnrecognizedExpressionException();
                        String savedField= (String) storage.get(varName);
                        int fieldIntValue= Integer.parseInt(field.getValue());
                        int intValue= Integer.parseInt(savedField);
                        return fieldIntValue >= intValue;
                   }
                    else 
                        throw new UnrecognizedExpressionException();
                }
                else 
                    throw new UnrecognizedExpressionException();
            } 
            else 
                throw new UnrecognizedExpressionException();
        } catch (UnrecognizedTokenException ex) {
            throw new UnrecognizedExpressionException();
        }
    }
    
}


